package com.bh.dispatch.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bh.common.annotation.DataDictClass;
import com.bh.common.basemapper.UpdateBatchWrapper;
import com.bh.common.constant.Entity;
import com.bh.common.exception.ServiceException;
import com.bh.common.utils.DateUtils;
import com.bh.common.utils.RedisCodeUtil;
import com.bh.common.utils.SecurityUtils;
import com.bh.common.utils.StringUtils;
import com.bh.dispatch.convert.JcDispatchConvert;
import com.bh.dispatch.domain.JcDispatch;
import com.bh.dispatch.mapper.JcDispatchMapper;
import com.bh.dispatch.service.IJcDispatchService;
import com.bh.dispatch.vo.JcDispatchVo;
import com.bh.extend.domain.JcAbnormal;
import com.bh.extend.domain.JcAbnormalDetail;
import com.bh.extend.service.IJcAbnormalDetailService;
import com.bh.extend.service.IJcAbnormalService;
import com.bh.fee.domain.JcFeeType;
import com.bh.fee.mapper.JcFeeTypeMapper;
import com.bh.kysys.domain.JcSysOrganization;
import com.bh.kysys.mapper.JcSysOrganizationMapper;
import com.bh.ledger.domain.JcLedgerDetail;
import com.bh.ledger.domain.JcVerificationZb;
import com.bh.ledger.mapper.JcLedgerDetailMapper;
import com.bh.order.domain.JcLed;
import com.bh.order.domain.JcOrder;
import com.bh.order.domain.JcPresco;
import com.bh.order.mapper.JcLedMapper;
import com.bh.order.mapper.JcOrderMapper;
import com.bh.order.mapper.JcPrescoMapper;
import com.bh.ledger.mapper.JcVerificationZbMapper;
import com.bh.order.service.IJcOrderTrackService;
import com.bh.vehicle.domain.JcCarrier;
import com.bh.vehicle.mapper.JcCarrierMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 提派单Service业务层处理
 *
 * @author slx
 * @date 2023-04-24
 */
@Service
public class JcDispatchServiceImpl extends ServiceImpl<JcDispatchMapper, JcDispatch> implements IJcDispatchService {
    @Autowired
    private JcDispatchMapper jcDispatchMapper;
    @Autowired
    private JcDispatchConvert jcDispatchConvert;
    @Autowired
    private JcCarrierMapper carrierMapper;
    @Autowired
    private JcSysOrganizationMapper jcSysOrganizationMapper;
    @Autowired
    private JcFeeTypeMapper jcFeeTypeMapper;
    @Autowired
    private JcLedgerDetailMapper ledgerDetailMapper;
    @Autowired
    private RedisCodeUtil redisCodeUtil;
    @Autowired
    private JcPrescoMapper prescoMapper;
    @Autowired
    private JcVerificationZbMapper verificationZbMapper;
    @Autowired
    private JcLedMapper ledMapper;
    @Autowired
    private JcOrderMapper orderMapper;
    @Autowired
    private IJcOrderTrackService jcOrderTrackService;
    @Autowired
    private IJcAbnormalService abnormalService;
    @Autowired
    private IJcAbnormalDetailService abnormalDetailService;

    /**
     * 查询提派单
     *
     * @param id 提派单主键
     * @return 提派单
     */
    @Override
    public JcDispatchVo selectJcDispatchById(Long id) {
        JcDispatch jcDispatch = jcDispatchMapper.selectById(id);
        JcDispatchVo dispatchVO = jcDispatchConvert.toVo(jcDispatch);
        List<JcLedgerDetail> ledgerDetails = ledgerDetailMapper.selectJcLedgerDetailListByJcDispatchId(id);
        if (ledgerDetails != null && ledgerDetails.size() > 0) {
            for (JcLedgerDetail ledgerDetail : ledgerDetails) {
                if ("DPYF".equals(ledgerDetail.getJcFeeTypeCode())) {
                    dispatchVO.setCost1(ledgerDetail.getAmount());
                }
                if ("DPSLF".equals(ledgerDetail.getJcFeeTypeCode())) {
                    dispatchVO.setCost2(ledgerDetail.getAmount());
                }

                if ("DPXHF".equals(ledgerDetail.getJcFeeTypeCode())) {
                    dispatchVO.setCost3(ledgerDetail.getAmount());
                }
                if ("DPJTF".equals(ledgerDetail.getJcFeeTypeCode())) {
                    dispatchVO.setCost4(ledgerDetail.getAmount());
                }
            }
        }
        return dispatchVO;
    }

    /**
     * 查询提派单列表
     *
     * @param jcDispatch 提派单
     * @return 提派单
     */
    @DataDictClass
    @Override
    public List<JcDispatch> selectJcDispatchList(JcDispatch jcDispatch) {
        return jcDispatchMapper.selectJcDispatchList(jcDispatch);
    }

    /**
     * 新增提派单
     *
     * @param dispatchVo 提派单
     * @return 结果
     */
    @Override
    public int insertJcDispatch(JcDispatchVo dispatchVo) {
        dispatchVo.setCode(redisCodeUtil.getDispatchCode());
        dispatchVo.setStatus(Entity.ACTIVE);
        dispatchVo.setCreateTime(DateUtils.getNowDate());
        dispatchVo.setCreateName(SecurityUtils.getUsername());

        //如果是个体司机 则承运商为空
        if (dispatchVo.getCarrierType() == 1) {
            dispatchVo.setJcCarrierId(null);
        } else {
            //如果是承运商
            if (dispatchVo.getJcCarrierId() == null) {
                throw new ServiceException("承运商必须选择");
            }

            JcCarrier carrier = carrierMapper.selectById(dispatchVo.getJcCarrierId());
            Date startTime = carrier.getStartTime();
            Date endTime = carrier.getEndTime();
            boolean b = DateUtils.belongCalendar(dispatchVo.getDateBilling(), startTime, endTime);
            if (b) {
                //计算承运商是否超期
                dispatchVo.setIsOverdueCarrier(0);
            } else {
                dispatchVo.setIsOverdueCarrier(1);
            }

            JcSysOrganization org = jcSysOrganizationMapper.selectById(dispatchVo.getJcOrganizationId());
            if (org.getIsOverdueCarrier() == 0 && !b) {
                throw new ServiceException("承运商已超期");
            }
        }
        JcDispatch dispatch = jcDispatchConvert.toEntity(dispatchVo);
        int num = jcDispatchMapper.insert(dispatch);
        // 组装 LedgerDetail
        dispatchVo.setId(dispatch.getId());
        List<JcLedgerDetail> ledgerDetails = insertLedgerDetails(dispatchVo);
        ledgerDetailMapper.insertBatch(ledgerDetails);
        return num;
    }

    /**
     * 修改提派单
     *
     * @param dispatchVo 提派单
     * @return 结果
     */

    @Override
    public int updateJcDispatch(JcDispatchVo dispatchVo) {
        JcDispatch old = jcDispatchMapper.selectById(dispatchVo.getId());
        if (old.getStatus() > 2) {
            throw new ServiceException("请使用异常修改");
        }
        dispatchVo.setModifyName(SecurityUtils.getUsername());
        dispatchVo.setModifyTime(DateUtils.getNowDate());


        //如果是个体司机 则承运商为空
        if (dispatchVo.getCarrierType() == 1) {
            dispatchVo.setJcCarrierId(null);
        } else {
            //如果是承运商
            if (dispatchVo.getJcCarrierId() == null) {
                throw new ServiceException("承运商必须选择");
            }

            JcCarrier carrier = carrierMapper.selectById(dispatchVo.getJcCarrierId());
            Date startTime = carrier.getStartTime();
            Date endTime = carrier.getEndTime();
            boolean b = DateUtils.belongCalendar(dispatchVo.getDateBilling(), startTime, endTime);
            if (b) {
                //计算承运商是否超期
                dispatchVo.setIsOverdueCarrier(0);
            } else {
                dispatchVo.setIsOverdueCarrier(1);
            }

            JcSysOrganization org = jcSysOrganizationMapper.selectById(dispatchVo.getJcOrganizationId());
            if (org.getIsOverdueCarrier() == 0 && !b) {
                throw new ServiceException("承运商已超期");
            }
        }

        // 先删除
        ledgerDetailMapper.deleteJcLedgerDetailByJcDispatchId(dispatchVo.getId());
        // 保存费用明细
        List<JcLedgerDetail> ledgerDetails = insertLedgerDetails(dispatchVo);
        ledgerDetailMapper.insertBatch(ledgerDetails);
        return jcDispatchMapper.updateById(jcDispatchConvert.toEntity(dispatchVo));
    }


    public List<JcLedgerDetail> insertLedgerDetails(JcDispatchVo dispatchVo) {
        // 组装 LedgerDetail
        List<JcFeeType> feeTypes = jcFeeTypeMapper.selectJcFeeTypeByCodes(Arrays.asList("DPYF", "DPSLF", "DPXHF", "DPJTF"));
        if (feeTypes == null || feeTypes.isEmpty()) {
            throw new ServiceException("费用类型未配置");
        }
        Map<String, JcFeeType> feeTypeMap = feeTypes.stream().collect(Collectors.toMap(JcFeeType::getCode, Function.identity()));
        List<JcLedgerDetail> ledgerDetails = new ArrayList<>();
        if (dispatchVo.getCost1().compareTo(BigDecimal.ZERO) > 0) {
            JcLedgerDetail cost1 = new JcLedgerDetail();
            cost1.setAmount(dispatchVo.getCost1());
            cost1.setCategory(1);
            cost1.setInput(dispatchVo.getCost1().multiply(dispatchVo.getRate()));
            cost1.setTaxrate(dispatchVo.getRate());
            cost1.setType(2);
            cost1.setJcFeeTypeId(feeTypeMap.get("DPYF").getId());
            cost1.setJcFeeTypeCode("DPYF");
            cost1.setIsConfirm(0);
            cost1.setStatus(1);
            cost1.setJcDispatchId(dispatchVo.getId());
            cost1.setCreateName(SecurityUtils.getUsername());
            cost1.setCreateTime(DateUtils.getNowDate());
            ledgerDetails.add(cost1);
        }

        if (dispatchVo.getCost2().compareTo(BigDecimal.ZERO) > 0) {
            JcLedgerDetail cost2 = new JcLedgerDetail();
            cost2.setAmount(dispatchVo.getCost2());
            cost2.setCategory(1);
            cost2.setInput(dispatchVo.getCost2().multiply(dispatchVo.getRate()));
            cost2.setTaxrate(dispatchVo.getRate());
            cost2.setType(2);
            cost2.setJcFeeTypeId(feeTypeMap.get("DPSLF").getId());
            cost2.setJcFeeTypeCode("DPSLF");
            cost2.setIsConfirm(0);
            cost2.setStatus(1);
            cost2.setJcDispatchId(dispatchVo.getId());
            cost2.setCreateName(SecurityUtils.getUsername());
            cost2.setCreateTime(DateUtils.getNowDate());
            ledgerDetails.add(cost2);
        }

        if (dispatchVo.getCost3().compareTo(BigDecimal.ZERO) > 0) {
            JcLedgerDetail cost3 = new JcLedgerDetail();
            cost3.setAmount(dispatchVo.getCost3());
            cost3.setCategory(1);
            cost3.setInput(dispatchVo.getCost3().multiply(dispatchVo.getRate()));
            cost3.setTaxrate(dispatchVo.getRate());
            cost3.setType(2);
            cost3.setJcFeeTypeId(feeTypeMap.get("DPXHF").getId());
            cost3.setJcFeeTypeCode("DPXHF");
            cost3.setIsConfirm(0);
            cost3.setStatus(1);
            cost3.setJcDispatchId(dispatchVo.getId());
            cost3.setCreateName(SecurityUtils.getUsername());
            cost3.setCreateTime(DateUtils.getNowDate());
            ledgerDetails.add(cost3);
        }

        if (dispatchVo.getCost4().compareTo(BigDecimal.ZERO) > 0) {
            JcLedgerDetail cost4 = new JcLedgerDetail();
            cost4.setAmount(dispatchVo.getCost4());
            cost4.setCategory(1);
            cost4.setInput(dispatchVo.getCost4().multiply(dispatchVo.getRate()));
            cost4.setTaxrate(dispatchVo.getRate());
            cost4.setType(2);
            cost4.setJcFeeTypeId(feeTypeMap.get("DPJTF").getId());
            cost4.setJcFeeTypeCode("DPJTF");
            cost4.setIsConfirm(0);
            cost4.setStatus(1);
            cost4.setJcDispatchId(dispatchVo.getId());
            cost4.setCreateName(SecurityUtils.getUsername());
            cost4.setCreateTime(DateUtils.getNowDate());
            ledgerDetails.add(cost4);
        }
        return ledgerDetails;
    }

    /**
     * 批量删除提派单
     *
     * @param ids 需要删除的提派单主键
     * @return 结果
     */
    @Override
    public int deleteJcDispatchByIds(Long[] ids) {
        return jcDispatchMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除提派单信息
     *
     * @param id 提派单主键
     * @return 结果
     */
    @Override
    public int deleteJcDispatchById(Long id) {
        return jcDispatchMapper.deleteById(id);
    }

    @Override
    public int startExe(Long[] ids) {
        List<JcDispatch> dispatches = jcDispatchMapper.selectBatchIds(Arrays.asList(ids));
        int num = 0;
        for (JcDispatch dispatch : dispatches) {
            Date timestamp = new Date();
            if (dispatch.getStatus() == 2) {
                dispatch.setPlanStartTime(timestamp);
                dispatch.setStatus(3);
                dispatch.setModifyName(SecurityUtils.getUsername());
                dispatch.setModifyTime(timestamp);
                num += jcDispatchMapper.updateById(dispatch);
                //  List<Led> leds = single.getLeds();
                List<JcPresco> prescos = prescoMapper.selectJcPrescoListByJcDispatchId(dispatch.getId());
                if (prescos != null && !prescos.isEmpty()) {
                    for (JcPresco presco : prescos) {
                        presco.setStatus(3);
                    }
                    prescoMapper.updateBatch(prescos, new UpdateBatchWrapper<JcPresco>().setUpdateFields(
                            JcPresco::getStatus
                    ));
                }
            }
            List<JcLedgerDetail> ledgerDetails = ledgerDetailMapper.selectJcLedgerDetailListByJcDispatchId(dispatch.getId());
            BigDecimal amount = BigDecimal.ZERO;
            BigDecimal input = BigDecimal.ZERO;
            for (JcLedgerDetail ledgerDetail : ledgerDetails) {
                amount = amount.add(ledgerDetail.getAmount());
                input = input.add(ledgerDetail.getInput());
            }
            if (amount.compareTo(BigDecimal.ZERO) > 0) {
                JcVerificationZb verificationZb = new JcVerificationZb();
                verificationZb.setJcDispatchId(dispatch.getId());
                verificationZb.setJcOrderId(SecurityUtils.getOrgId());
                verificationZb.setHxStatus(0);
                verificationZb.setWhxMoney(amount);
                verificationZb.setZinput(input);
                verificationZb.setZmoney(amount);
                verificationZb.setTzSource(0L);
                verificationZb.setType(1);
                verificationZb.setHxMoney(BigDecimal.ZERO);
                verificationZbMapper.insert(verificationZb);
            }
            //修改单据状态
            List<JcLed> leds = ledMapper.selectJcLedListByJcDispatchId(dispatch.getId());
            for (JcLed led : leds) {
                int type = led.getType();
                //提货
                if (type == 0) {
                    //提货中
                    led.setStatus(22);
                }
                //派送
                if (type == 1) {
                    //派送中
                    led.setStatus(23);
                    JcOrder order = orderMapper.selectById(led.getJcOrderId());
                    jcOrderTrackService.addTrack(led.getJcOrderId(), "您的分段订单:" + led.getCode() + "  已经开始派送");
                    boolean s = false;
                    // order 对应的所有 led 的状态都是23，则order状态改为24
                    List<JcLed> ordLeds = ledMapper.selectJcLedListByOrderId(led.getJcOrderId());
                    for (JcLed ordLed : ordLeds) {
                        if (ordLed.getStatus() != 23) {
                            s = true;
                            break;
                        }
                    }
                    if (!s) {
                        order.setStatus(24);
                        orderMapper.updateById(order);
                    }
                }
            }
        }
        return num;
    }

    @Override
    public int endExe(Long[] ids) {
        Date timestamp = new Date();
        List<JcDispatch> dispatches = jcDispatchMapper.selectBatchIds(Arrays.asList(ids));
        int num = 0;
        for (JcDispatch dispatch : dispatches) {
            //修改单据状态
            List<JcLed> leds = ledMapper.selectJcLedListByJcDispatchId(dispatch.getId());
            for (JcLed led : leds) {
                int type = led.getType();
                if (type == 0) {
                    //提货
                    led.setStatus(88); //提货完毕
                    JcPresco presco = prescoMapper.selectById(led.getJcPrescoId());
                    boolean s = false;
                    List<JcLed> leds1 = ledMapper.selectByPrescoId(presco.getId());
                    for (JcLed l : leds1) {
                        int status = l.getStatus();
                        if (status == 88) {
                            //如果等于配载和待提货
                            s = true;
                            break;
                        }
                    }
                    if (s) {
                        presco.setStatus(4); //提货完毕
                    }
                }
                if (type == 1) { //派送
                    led.setStatus(24); //派送完毕
                    JcOrder order = orderMapper.selectById(led.getJcOrderId());
                    jcOrderTrackService.addTrack(led.getJcOrderId(), "您的分段订单:" + led.getCode() + "  已经派送完毕");
                    boolean s = false;
                    List<JcLed> leds1 = ledMapper.selectJcLedListByOrderId(led.getJcOrderId());
                    for (JcLed l : leds1) {
                        int status = l.getStatus();
                        if (status == 24) {
                            //如果等于配载和待提货
                            s = true;
                            break;
                        }
                    }
                    if (s) {
                        order.setStatus(24);
                    }
                }
                dispatch.setStatus(4);
                dispatch.setPlanEndTime(timestamp);
                dispatch.setModifyName(SecurityUtils.getUsername());
                dispatch.setModifyTime(timestamp);
                num += jcDispatchMapper.updateById(dispatch);
            }
        }
        return num;
    }

    @Override
    public int saveAbnormal(JcDispatchVo dispatch, String abnormal) {
        if (StringUtils.isEmpty(abnormal)) {
            throw new ServiceException("请填写异常修改原因");
        }
        boolean sb = dispatch.getStatus() == 0 || dispatch.getStatus() == 1;
        if (sb) {
            throw new ServiceException("不能异常修改保存状态的单据");
        }
        JcDispatch ns = this.getById(dispatch.getId());
        ns.setIsAbnormail(1);

        //生成异常单头
        JcAbnormal a = new JcAbnormal();
        a.setJcOrganizationId(SecurityUtils.getOrgId());
        a.setType(2);
        a.setTime(DateUtils.getNowDate());
        a.setDescription(abnormal);
        List<JcAbnormalDetail> abnormalList = abnormalDetailService.getAbnormalList(ns, dispatch);
        //组装Ledger
        List<JcLedgerDetail> ledgerDetails = insertLedgerDetails(dispatch);
        //原数据
        List<JcLedgerDetail> oldLedgerDetails = ledgerDetailMapper.selectJcLedgerDetailListByJcDispatchId(dispatch.getId());
        for (JcLedgerDetail sl : ledgerDetails) {
            //异常
            for (JcLedgerDetail slns : oldLedgerDetails) {
                //原数据
                if (sl.getFeeType().getId().equals(slns.getFeeType().getId())) {
                    BigDecimal amount = sl.getAmount();
                    BigDecimal taxRate = sl.getTaxrate();
                    BigDecimal input = sl.getInput();
                    BigDecimal amount2 = slns.getAmount();
                    BigDecimal taxRate2 = slns.getTaxrate();
                    BigDecimal input2 = slns.getInput();
                    if (amount.compareTo(amount2) != 0) {
                        //添加费用类型
                        JcAbnormalDetail abnormalDetail = new JcAbnormalDetail();
                        abnormalDetail.setSource("feeType");
                        abnormalDetail.setTarger(slns.getFeeType().getName());
                        abnormalDetail.setSourceValue(slns.getAmount().toString());
                        abnormalDetail.setTargerValue(sl.getAmount().toString());
                        abnormalList.add(abnormalDetail);
                        slns.setAmount(sl.getAmount());
                        slns.setTaxrate(sl.getTaxrate());
                        slns.setInput(slns.getAmount().divide(BigDecimal.ONE.add(slns.getTaxrate()), 2, RoundingMode.HALF_UP).multiply(slns.getTaxrate()));
                    }
                }
            }
        }


        a.setJcDispatchId(dispatch.getId());
        a.setNumber(abnormalList.size());
        abnormalService.insertJcAbnormal(a);
        for (JcAbnormalDetail abnormalDetail : abnormalList) {
            abnormalDetail.setJcAbnormalId(a.getId());
            abnormalDetail.setCreateName(SecurityUtils.getUsername());
            abnormalDetail.setCreateTime(new Date());
        }
        abnormalDetailService.saveBatch(abnormalList);
        JcDispatch jcDispatch = jcDispatchConvert.toEntity(dispatch);
        jcDispatch.setModifyName(SecurityUtils.getUsername());
        jcDispatch.setModifyTime(new Date());
        return jcDispatchMapper.updateById(jcDispatch);
    }
}
